import {intersectionWith, isEqual, mergeWith, unionWith} from 'lodash-es';
import {isArray, isObject} from '@/utils/is';
import type { App, Plugin } from 'vue';
import { dateUtil } from '@/utils/dateUtil';

export const withInstall = <T>(component: T, alias?: string) => {
    const comp = component as any;
    comp.install = (app: App) => {
        app.component(comp.name || comp.displayName, (component as any));
        if (alias) {
            app.config.globalProperties[alias] = component;
        }
    };
    return component as T & Plugin;
};


/**
 * @description:  Set ui mount node
 */
export function getPopupContainer(node?: HTMLElement): HTMLElement {
    return (node?.parentNode as HTMLElement) ?? document.body;
}

  
// dynamic use hook props
export function getDynamicProps<T, U>(props: T): Partial<U> {
    const ret: Recordable = {};

    Object.keys((props as any)).map((key) => {
        ret[key] = unref((props as Recordable)[key]);
    });

    return ret as Partial<U>;
}

/**
 * Recursively merge two objects.
 * 递归合并两个对象。
 *
 * @param source The source object to merge from. 要合并的源对象。
 * @param target The target object to merge into. 目标对象，合并后结果存放于此。
 * @param mergeArrays How to merge arrays. Default is "replace".
 *        如何合并数组。默认为replace。
 *        - "union": Union the arrays. 对数组执行并集操作。
 *        - "intersection": Intersect the arrays. 对数组执行交集操作。
 *        - "concat": Concatenate the arrays. 连接数组。
 *        - "replace": Replace the source array with the target array. 用目标数组替换源数组。
 * @returns The merged object. 合并后的对象。
 */
export function deepMerge<T extends object | null | undefined, U extends object | null | undefined>(
    source: T,
    target: U,
    mergeArrays: 'union' | 'intersection' | 'concat' | 'replace' = 'replace',
): T & U {
    if (!target) {
        return source as T & U;
    }
    if (!source) {
        return target as T & U;
    }
    return mergeWith({}, source, target, (sourceValue, targetValue) => {
        if (isArray(targetValue) && isArray(sourceValue)) {
            switch (mergeArrays) {
                case 'union':
                    return unionWith(sourceValue, targetValue, isEqual);
                case 'intersection':
                    return intersectionWith(sourceValue, targetValue, isEqual);
                case 'concat':
                    return sourceValue.concat(targetValue);
                case 'replace':
                    return targetValue;
                default:
                    throw new Error(`Unknown merge array strategy: ${mergeArrays as string}`);
            }
        }
        if (isObject(targetValue) && isObject(sourceValue)) {
            return deepMerge(sourceValue, targetValue, mergeArrays);
        }
        return undefined;
    });
}

/**
 * 防抖
 */
export const debounce = (() => {
    let timer: string | number | NodeJS.Timeout | null | undefined = null;
    return (callback: () => void, wait = 800) => {
        timer && clearTimeout(timer)
        timer = setTimeout(callback, wait)
    }
})();

/**
 * 获取树的所有id值
 * @param arr 列表
 * @param key 过滤字段
 */
export const getTreeAllIds = (arr: any[], key='id') => {
    let ids: any[] = [];
    arr.forEach((item: any) => {
        if(item[key] || item[key] >= 0){
            ids.push(item[key]);
        }
        if(item.children && item?.children.length > 0){
            ids =ids.concat(getTreeAllIds(item.children));
        }
    });
    return ids;
};

/**
 * @description:  导出文件下载处理
 * @param { BlobPart } data 接口返回的文件流
 * @param { string } name 下载的文件名称
 **/
export const downLoadExcelFile = (data:BlobPart, name:string, config?:object) => {
    const downConfig = { showDate: true };
    if(config && Object.keys(config).length){ 
        Object.assign(downConfig, config); 
    }
    const blob = new Blob([data], {
        type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    });
    const url = window.URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.style.display = 'none';
    link.href = url;
    const date = dateUtil(new Date).format('YYYYMMDDHHmmss');
    link.setAttribute('download', (downConfig['showDate'] ? `${name}-${date}` : name) || 'template.xls');
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
};

/**
 * @description:  随机生成数字
 **/
export const mathRand = () => { 
	let num = ''; 
	for(let i = 0 ; i < 6 ; i ++) { 
		num+=Math.floor(Math.random()*10); 
	} 
	return num ;
}

/**
 * @description:金额保留指定小数点位数
 **/
export const getFloatDecimal = (val: any) => {
	var num=0.00;
	try{
		num = parseFloat(val);
	}catch(e){
		num=0.00;	
	}
	return num.toFixed(2);
	//var re = /([0-9]+\.[0-9]{2})[0-9]*/;
	//var aNew = val.replace(re,"$1");
	//return aNew;
};

/**
 * @description: 递归获取树形数据
 * @param { any[] } dataScoure 未处理的数组
 * @param { number } parentId 第一层父级id;
 * @return { any[] }
 **/
export const useTreeData = (dataScoure: any[], parentId=0): any[] => {

    if(!dataScoure || !dataScoure.length) return [];

    const LeadList = dataScoure.filter((item:any)=> item.parentId == parentId);
    
    function handleRecursion (dataMap: Array<any>) {
        dataMap.forEach((item:any) => {
            // 查找对应的子级数据
            const sameList = dataScoure.filter((sItem:any)=> sItem['parentId'] == item['id']);

            if(sameList && sameList.length){
                item['children'] = sameList || []; 
            }
            else {
                item['children'] = [];
            }
            
            if(sameList.length > 0){
                handleRecursion(item['children']);
            }
        });
    }

    handleRecursion(LeadList);

    return LeadList;
};

/**
 * @description: 将金额用逗号隔开
 **/
export const tuFmoney = (s: any, n: any=0) => {
    n = n > 0 && n <= 20 ? n : 2; 
	s = parseFloat((s + '').replace(/[^\d\.-]/g, '')).toFixed(n) + ''; 
	let l = s.split('.')[0].split('').reverse(), r = s.split('.')[1]; 
	let t = ''; 
	for (let i = 0; i < l.length; i++) { 
	    t += l[i] + ((i + 1) % 3 == 0 && (i + 1) != l.length ? ',' : ''); 
	} 
	return t.split('').reverse().join('') + '.' + r; 
};